package com.xuzimian.global.demo.spring.security.oauth2.resource.config;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.Map;


@EnableResourceServer
@EnableWebSecurity
@Configuration
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
    private static final Log logger = LogFactory.getLog(ResourceServerConfigurer.class);
    @Autowired
    private OAuth2ProtectedResourceDetails details;

    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;
    @Autowired
    private AuthenticationEntryPoint denialAuthenticationEntryPoint;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

        http.csrf().disable();
        http.exceptionHandling()
                .authenticationEntryPoint(denialAuthenticationEntryPoint);
        http.logout().logoutUrl("/oauth/logout")
                .logoutSuccessHandler(this.logoutSuccessHandler);

        http.authorizeRequests()
                .anyRequest().authenticated();

    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("risk").stateless(true);
    }



    @Bean
    public DefaultTokenServices jwtTokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setTokenStore(tokenStore());
        return services;
    }



    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        try {
            //设置用于解码的非对称加密的公钥
            converter.setVerifierKey(getKeyFromAuthorizationServer());
        } catch (ResourceAccessException ex) {
            logger.warn("Failed to fetch token key (you may need to refresh "
                    + "when the auth server is back)");
            throw new RuntimeException("请先启动本地的spring-security-oauth2-server程序服务，并保证端口是80.否则将不能获取到证书。");
        }

        return converter;
    }

    @Bean
    public OAuth2ProtectedResourceDetails remote() {
        AuthorizationCodeResourceDetails resourceDetails = new AuthorizationCodeResourceDetails();
        resourceDetails.setAccessTokenUri("http://localhost/oauth/token");
        resourceDetails.setUserAuthorizationUri("http://localhost/oauth/authorize");
        resourceDetails.setClientId("ssoclient");
        resourceDetails.setClientSecret("ssosecret");
        resourceDetails.setScope(Arrays.asList("all"));
        return resourceDetails;
    }

    private String getKeyFromAuthorizationServer() {
        HttpHeaders headers = new HttpHeaders();
        String username = details.getClientId();
        String password = details.getClientSecret();
        if (username != null && password != null) {
            byte[] token = Base64.encode((username + ":" + password).getBytes());
            headers.add("Authorization", "Basic " + new String(token));
        }

        HttpEntity<Void> request = new HttpEntity<Void>(headers);
        return (String) new RestTemplate()
                .exchange("http://localhost/oauth/token_key", HttpMethod.GET, request, Map.class).getBody()
                .get("value");
    }

}
